package edu.java.homework.hw09.exercises.nikolay.food.salad;

import edu.java.homework.hw09.exercises.nikolay.food.ingredient.type.MilkType;
import edu.java.homework.hw09.exercises.nikolay.food.ingredient.type.SpiceType;
import edu.java.homework.hw09.exercises.nikolay.food.ingredient.type.VegetableType;
import edu.java.homework.hw09.exercises.nikolay.food.product.MilkProduct;
import edu.java.homework.hw09.exercises.nikolay.food.product.Product;
import edu.java.homework.hw09.exercises.nikolay.food.product.SpiceProduct;
import edu.java.homework.hw09.exercises.nikolay.food.product.VegetableProduct;

public class ShoppSaladFactory extends SaladFactory {

    // --- Class Variables -----------------------------------------------------

    private static ShoppSaladFactory instance;

    // --- Constructors --------------------------------------------------------

    private ShoppSaladFactory() {
    }

    // --- Methods (Singleton) -------------------------------------------------

    public static ShoppSaladFactory instance() {
	if (instance == null) {
	    instance = new ShoppSaladFactory();
	}
	return instance;
    }

    // --- Methods (Salad - Template Method) -----------------------------------

    @Override
    protected Salad initSalad() {
	String prefix = "[init-salad]\t\t";
	System.out.println(prefix + "Initializing the products...");
	MilkProduct whiteCheese = new MilkProduct(MilkType.WHITE_CHEESE, 50);
	VegetableProduct[] vegetables = getVegetables();
	SpiceProduct[] spices = getSpices();
	int price = calculatePrice(whiteCheese, vegetables, spices);

	ShoppSalad shoppSalad = new ShoppSalad(vegetables, whiteCheese, spices,
		price);
	System.out.println(prefix + "Products initialized.");

	return shoppSalad;
    }

    @Override
    protected void washProducts(Salad salad) {
	if (salad == null) {
	    throw new IllegalArgumentException(
		    "Invalid argument - salad: null.");
	}
	if (!(salad instanceof ShoppSalad)) {
	    throw new IllegalArgumentException(
		    "Invalid argument - salad: not of type ShoppSalad.");
	}
	ShoppSalad shoppSalad = (ShoppSalad) salad;
	String prefix = "[wash-products]\t\t";
	System.out.print(prefix + "Washing the products: ");
	VegetableProduct[] vegetables = shoppSalad.getVegetables();
	for (VegetableProduct vegetable : vegetables) {
	    System.out.print(vegetable + "; ");
	}
	System.out.println();
	System.out.println(prefix + "Washing finished.");
    }

    @Override
    protected void boilProducts(Salad salad) {
	// do nothing
    }

    @Override
    protected void cutProducts(Salad salad) {
	if (salad == null) {
	    throw new IllegalArgumentException(
		    "Invalid argument - salad: null.");
	}
	if (!(salad instanceof ShoppSalad)) {
	    throw new IllegalArgumentException(
		    "Invalid argument - salad: not of type ShoppSalad.");
	}
	ShoppSalad shoppSalad = (ShoppSalad) salad;
	String prefix = "[cut-products]\t\t";
	System.out.print(prefix + "Cutting products: ");

	// cutting...
	printSemicolonSeparatedList(shoppSalad.getVegetables());
	System.out.println(shoppSalad.getWhiteCheese() + COMMA);

	System.out.println(prefix + "Cutting finished.");
    }

    @Override
    protected void grateProducts(Salad salad) {
	if (salad == null) {
	    throw new IllegalArgumentException(
		    "Invalid argument - salad: null.");
	}
	if (!(salad instanceof ShoppSalad)) {
	    throw new IllegalArgumentException(
		    "Invalid argument - salad: not of type ShoppSalad.");
	}
	ShoppSalad shoppSalad = (ShoppSalad) salad;
	String prefix = "[grate-products]\t\t";
	System.out.print(prefix + "Grating products: ");

	// grating...
	System.out.print(shoppSalad.getWhiteCheese() + COMMA);
	System.out.println();

	System.out.println(prefix + "Grating finished.");

    }

    @Override
    protected void mixProducts(Salad salad) {
	if (salad == null) {
	    throw new IllegalArgumentException(
		    "Invalid argument - salad: null.");
	}
	if (!(salad instanceof ShoppSalad)) {
	    throw new IllegalArgumentException(
		    "Invalid argument - salad: not of type ShoppSalad.");
	}
	ShoppSalad shoppSalad = (ShoppSalad) salad;
	String prefix = "[mix-products]\t\t";
	System.out.print(prefix + "Mixing products: ");

	// mixing...
	printSemicolonSeparatedList(shoppSalad.getVegetables());
	System.out.print(shoppSalad.getWhiteCheese() + COMMA);
	printSemicolonSeparatedList(shoppSalad.getSpices());
	System.out.println();

	System.out.println(prefix + "Mixing finished.");

    }

    // --- Methods (Salad) -----------------------------------------------------

    /**
     * 100 g tomatoes, 50 g cucumbers, 1 raw hot pepper, 20 g onion, 10 g raw
     * green pepper, 5 olives, 10 g parsley
     */
    @Override
    protected VegetableProduct[] getVegetables() {
	VegetableProduct tomatoe = new VegetableProduct(VegetableType.TOMATO,
		100);
	VegetableProduct cucumber = new VegetableProduct(
		VegetableType.CUCUMBER, 50);
	VegetableProduct hotPepper = new VegetableProduct(
		VegetableType.RAW_HOT_PEPPER, 1);
	VegetableProduct onion = new VegetableProduct(VegetableType.ONION, 20);
	VegetableProduct greenPepper = new VegetableProduct(
		VegetableType.RAW_GREEN_PEPPER, 10);
	VegetableProduct olives = new VegetableProduct(VegetableType.OLIVE, 5);
	VegetableProduct parsley = new VegetableProduct(VegetableType.PARSLEY,
		10);

	VegetableProduct[] vegetables = new VegetableProduct[] { tomatoe,
		cucumber, hotPepper, onion, greenPepper, olives, parsley };

	return vegetables;
    }

    /**
     * 5 g salt, 10 g oil
     */
    @Override
    protected SpiceProduct[] getSpices() {
	SpiceProduct oil = new SpiceProduct(SpiceType.OLIVE_OIL, 10);
	SpiceProduct salt = new SpiceProduct(SpiceType.SALT, 5);

	SpiceProduct[] spices = new SpiceProduct[] { oil, salt };

	return spices;
    }

    // --- Methods -------------------------------------------------------------

    private int calculatePrice(MilkProduct whiteCheese, Product[]... products) {
	int price = 0;
	price += whiteCheese.getPrice();
	for (Product[] productsArr : products) {
	    for (Product product : productsArr) {
		price += product.getPrice();
	    }
	}
	return price;
    }
}
